#ifndef _IFLYTEK_ASR_REQUEST_PARAM_H_
#define _IFLYTEK_ASR_REQUEST_PARAM_H_
#include<string>
#include"asrInst.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define PBKDF2_SHA256_STATIC
#define PBKDF2_SHA256_IMPLEMENTATION
#include "pbkdf2_sha256.h"
#include <time.h>//only for linux
#include <ctype.h>//only for linux


class iflytekAsrRequestParam
{
public:

	iflytekAsrRequestParam(char* appId, char* apiKey,char* apiSecret)
	{
		if(appId)
		{
			APPID = new char[strlen(appId) +1];
			strcpy(APPID,appId);
			APPID[strlen(appId)]='\0';
		}
		if (apiKey)
		{
			APIKEY = new char[strlen(apiKey) +1];
			strcpy(APIKEY,apiKey);
			APIKEY[strlen(apiKey)] ='\0';
		}
		if (apiSecret)
		{
			APISECRET = new char[strlen(apiSecret) +1];
			strcpy(APISECRET,apiSecret);
			APISECRET[strlen(apiSecret)]='\0';
		}
		memset(_encodeStr,0, 1024);
	}
	~iflytekAsrRequestParam()
	{
		if(APPID)
		{
			delete[] APPID;
			APPID = NULL;
		}
		if(APIKEY)
		{
			delete[] APIKEY;
			APIKEY = NULL;
		}
		if(APISECRET)
		{
			delete[] APISECRET;
			APISECRET = NULL;
		}
	}
	void genEncodeStr(uint8_t *key, uint32_t klen, const uint8_t *msg, uint32_t mlen)
	{
		uint8_t md[SHA256_DIGESTLEN];
		HMAC_SHA256_CTX2 hmac;
		hmac_sha256_init(&hmac, key, klen);
		hmac_sha256_update(&hmac, msg, mlen);
		hmac_sha256_final(&hmac, md);
		/*uint8_t hexStr[SHA256_DIGESTLEN];
		const char HEX[] = "0123456789ABCDEF";
		printf("Get hex string :\n");
		for (uint32_t i = 0;  i < SHA256_DIGESTLEN; ++i)
		{
			hexStr[i] = HEX[md[i]/16]; 
			printf("%02X",md[i]);
		}
		printf("\n");*/
		uint8_t base64md[SHA256_DIGESTLEN*2];
		uint32_t iSize = base64_encode (static_cast<uint8_t*>(md),SHA256_DIGESTLEN,base64md);
		for(uint32_t i = 0; i < iSize; ++i)
			sprintf(_encodeStr + i,"%c",base64md[i]);
		printf("Get encode string %s\n",_encodeStr);
	}
	uint32_t base64_encode(const uint8_t *text, uint32_t text_len, uint8_t *encode)
	{
		uint32_t i, j;
		for (i = 0, j = 0; i+3 <= text_len; i+=3)
		{
			encode[j++] = alphabet_map[text[i]>>2];                             //取出第一个字符的前6位并找出对应的结果字符
			encode[j++] = alphabet_map[((text[i]<<4)&0x30)|(text[i+1]>>4)];     //将第一个字符的后2位与第二个字符的前4位进行组合并找到对应的结果字符
			encode[j++] = alphabet_map[((text[i+1]<<2)&0x3c)|(text[i+2]>>6)];   //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
			encode[j++] = alphabet_map[text[i+2]&0x3f];                         //取出第三个字符的后6位并找出结果字符
		}

		if (i < text_len)
		{
			uint32_t tail = text_len - i;
			if (tail == 1)
			{
				encode[j++] = alphabet_map[text[i]>>2];
				encode[j++] = alphabet_map[(text[i]<<4)&0x30];
				encode[j++] = '=';
				encode[j++] = '=';
			}
			else //tail==2
			{
				encode[j++] = alphabet_map[text[i]>>2];
				encode[j++] = alphabet_map[((text[i]<<4)&0x30)|(text[i+1]>>4)];
				encode[j++] = alphabet_map[(text[i+1]<<2)&0x3c];
				encode[j++] = '=';
			}
		}
		return j;
 	}
	uint32_t base64_encodeStr(char *text, uint32_t text_len, uint8_t *encode)
	{
		uint32_t i, j;
		for (i = 0, j = 0; i+3 <= text_len; i+=3)
		{
			encode[j++] = alphabet_map[text[i]>>2];                             //取出第一个字符的前6位并找出对应的结果字符
			encode[j++] = alphabet_map[((text[i]<<4)&0x30)|(text[i+1]>>4)];     //将第一个字符的后2位与第二个字符的前4位进行组合并找到对应的结果字符
			encode[j++] = alphabet_map[((text[i+1]<<2)&0x3c)|(text[i+2]>>6)];   //将第二个字符的后4位与第三个字符的前2位组合并找出对应的结果字符
			encode[j++] = alphabet_map[text[i+2]&0x3f];                         //取出第三个字符的后6位并找出结果字符
		}

		if (i < text_len)
		{
			uint32_t tail = text_len - i;
			if (tail == 1)
			{
				encode[j++] = alphabet_map[text[i]>>2];
				encode[j++] = alphabet_map[(text[i]<<4)&0x30];
				encode[j++] = '=';
				encode[j++] = '=';
			}
			else //tail==2
			{
				encode[j++] = alphabet_map[text[i]>>2];
				encode[j++] = alphabet_map[((text[i]<<4)&0x30)|(text[i+1]>>4)];
				encode[j++] = alphabet_map[(text[i+1]<<2)&0x3c];
				encode[j++] = '=';
			}
		}
		return j;
 	}
	char* getRFC1123Time(time_t t)
	{
		char *ret;
		struct tm *gmt = gmtime(&t);
		if (NULL == gmt)
			return NULL;
		ret = static_cast<char*>(malloc(30));
		snprintf(ret,30,RFC1123FORMAT, rfc1123_weekdays[gmt->tm_wday], gmt->tm_mday, 
        short_months[gmt->tm_mon], 1900 + gmt->tm_year, 
        gmt->tm_hour, gmt->tm_min, gmt->tm_sec);
		return ret;
	}
	
	unsigned char toHex(unsigned char x) 
	{ 
		return  x > 9 ? x + 55 : x + 48; 
	}
	std::string urlEncode(const std::string& str)
	{
		std::string strTemp = "";
		size_t length = str.length();
		for (size_t i = 0; i < length; i++)
		{
			if (isalnum((unsigned char)str[i]) || 
				(str[i] == '-') ||
				(str[i] == '_') || 
				(str[i] == '.') || 
				(str[i] == '~'))
				strTemp += str[i];
			else if (str[i] == ' ')
				strTemp += "+";
			else
			{
				strTemp += '%';
				strTemp += toHex((unsigned char)str[i] >> 4);
				strTemp += toHex((unsigned char)str[i] % 16);
			}
		}
		return strTemp;
	}


	std::string createUrl();
    		
	const char* getBusinessArgs() {return BUSINESSARGS;}
	std::string getFrame(int iMsgType,void* pBuf,int iBufLen)
	{
		if(FRAME_FIRST == iMsgType)
			return getFirstFrame(iMsgType,pBuf,iBufLen);
		else
			return std::string("{") + getCommonFrame(iMsgType,pBuf,iBufLen) + std::string("}");
	}
private:
	std::string getFirstFrame(int iType, void* pBuf, int iBufLen)
	{
		std::string ret;
		ret = std::string("{\"common\":{\"app_id\":\"") + std::string(APPID)
			 + std::string("\"},\"business\":") + BUSINESSARGS 
			 + std::string(",")  + getCommonFrame(iType,pBuf,iBufLen)+"}";
		return ret;
	} 
	std::string getCommonFrame(int iType, void* pBuf, int iBufLen)
	{
		std::string ret;
		char pType[2]={'\0'};
		sprintf(pType,"%d",iType);
		if(iBufLen > 0)
		{
			uint8_t bufMd[20480];
			const uint8_t * pText = reinterpret_cast<uint8_t *>(pBuf);
			uint32_t iSize = base64_encode(pText,iBufLen,bufMd);
			char audioData[20480] = {'\0'};
			for(uint32_t i = 0; i < iSize; i++)
				sprintf(audioData +i,"%c",bufMd[i]); 
			ret = std::string("\"data\": {\"status\":") + std::string(pType) 
				+ std::string(",\"format\": \"audio/L16;rate=8000\",") 
				+ std::string("\"audio\":\"") + std::string(audioData)
				+ std::string("\",\"encoding\": \"raw\"}");
		}
		else
			ret = std::string("\"data\": {\"status\":") + std::string(pType) + std::string("}");
		return ret;
	}
	std::string        _finalUrl;
	char          _encodeStr[1024];
	char*         APPID;
	char*         APIKEY;
	char*         APISECRET;
	static const char* BUSINESSARGS;//="{\"domain\": \"iat\", \"language\": \"zh_cn\", \"accent\": \"mandarin\", \"vinfo\":0,\"vad_eos\":100000}";
	//static constexpr char* BUSINESSARGS="{\"domain\": \"iat\", \"language\": \"zh_cn\", \"accent\": \"mandarin\"}";

	/* RFC1123: Sun, 06 Nov 1994 08:49:37 GMT 
 	* */
	static const  char * RFC1123FORMAT;
	static const uint8_t alphabet_map[];
	static const char *const rfc1123_weekdays[7];
	static const char *const short_months[12];
};
#endif
